package controller

import (
	"bytes"
	"errors"
	"fileService/common/output"
	"fileService/common/utils/fileTypeUtils"
	Config "fileService/config"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
)

//  单个文件上传最大大小
var singImageUploadSize int64 = 1024 * 1024 * 2

func uploadBeforeHandle(context *gin.Context) (header *multipart.FileHeader, err error) {

	file, header, err := context.Request.FormFile("file")
	if err != nil {
		return nil, err
	}
	if header.Size > singImageUploadSize {
		err = errors.New("最大单个上传文件为：" + strconv.FormatInt(singImageUploadSize/1024/1024, 10) + "m")
		return nil, err
	}
	defer file.Close()
	return header, nil

}

// 上传目录检测
func uploadCreateDir(bucket string, fileName string) string {
	saveDir := Config.Config.StorePath + bucket
	_, err := os.Stat(saveDir)
	if err != nil {
		_ = os.MkdirAll(saveDir, os.ModePerm)
	}
	// 保存路径
	return saveDir + "/" + fileName
}

func uploadAfterHandle() {

}

func checkEmpty(content string, context *gin.Context) error {
	if content==""{
		err:=errors.New("参数不能为空")
		output.Fail(context, err)
		return err
	}
	return nil
}

func getBucket(context *gin.Context) string {
	bucket := context.Request.FormValue("bucket")
	if bucket == "" {
		bucket = "default"
	}
	return bucket
}

func fileTypeFileHeaderCheck(file *multipart.FileHeader) bool {
	var byte_ []byte=make([]byte,5)
	fileOpen, _ := file.Open()
	fileOpen.Read(byte_)
	fileType:=fileTypeUtils.GetFileType(byte_)

	uploadType:=Config.Config.UploadType
	for i := range uploadType {
		if uploadType[i]==fileType {
			return true
		}
	}
	return false
}
func fileTypeByteCheck(byte_ []byte) bool {
	fileType:=fileTypeUtils.GetFileType(byte_)
	uploadType:=Config.Config.UploadType
	for i := range uploadType {
		if uploadType[i]==fileType {
			return true
		}
	}
	return false
}
/**
单文件上传
*/
func UploadFile(context *gin.Context) {
	bucket := getBucket(context)
	header, err := uploadBeforeHandle(context)
	if err != nil {
		output.Fail(context, err)
		return
	}

	filePath := uploadCreateDir(bucket, header.Filename)
	isAllow:=fileTypeFileHeaderCheck(header)
	if !isAllow{
		output.Fail(context, errors.New("非法文件类型"))
		return
	}
	err = context.SaveUploadedFile(header, filePath)
	if err != nil {
		output.Fail(context, err)
		return
	}
	output.Success(context, gin.H{
		"fileFull": Config.Config.Website + bucket + "/" + header.Filename,
		"file": bucket + "/" + header.Filename,
	})
}

/**
资源上传
*/
func UploadStream(context *gin.Context) {
	bucket := getBucket(context)
	fileUrl := context.Request.FormValue("file")
	if fileUrl == "" {
		output.Fail(context, errors.New("图片地址不能为空"))
		return
	}
	resp, err := http.Get(fileUrl)
	if err != nil {
		output.Fail(context, err)
		return
	}
	defer resp.Body.Close()
	bytes_, _ := ioutil.ReadAll(resp.Body)

	isAllow:=fileTypeByteCheck(bytes_[:5])
	if !isAllow{
		output.Fail(context, errors.New("非法文件类型"))
		return
	}

	if int64(len(bytes_)/1024) > singImageUploadSize {
		err = errors.New("最大单个上传文件为：" + strconv.FormatInt(singImageUploadSize/1024/1024, 10) + "m")
		output.Fail(context, err)
		return
	}
	fileName := path.Base(fileUrl)
	if fileName == "" {
		output.Fail(context, errors.New("文件不存在"))
		return
	}

	filePath := uploadCreateDir(bucket, fileName)
	file, err := os.Create(filePath)
	if err != nil {
		output.Fail(context, errors.New("文件上传失败"))
		return
	}
	defer file.Close()
	_, err = io.Copy(file,  bytes.NewReader(bytes_))
	if err != nil {
		output.Fail(context, err)
		return
	}
	output.Success(context, gin.H{
		"fileFull": Config.Config.Website + bucket + "/" + fileName,
		"file": bucket + "/" + fileName,
	})
}

/**
分片上传
*/
func UploadChunk(context *gin.Context) {
	bucket := getBucket(context)
	if checkEmpty(bucket,context)!=nil{
		return
	}
	fileName := context.Request.FormValue("fileName")
	if checkEmpty(fileName,context)!=nil{
		return
	}
	chunk:= context.Request.FormValue("chunk")
	if checkEmpty(chunk,context)!=nil{
		return
	}

	chunkSize:= context.Request.FormValue("chunkSize")
	if checkEmpty(chunkSize,context)!=nil{
		return
	}

	//当前用户
	curUser:="woddp"


	// 获取文件名称没有后缀和文件后缀
	fileNameExt:=path.Ext(fileName)
	//缓存目录
	cachePath:="cache/"+curUser+"/"+strings.Replace(fileName,fileNameExt,"",1)
	// 是否上全完毕
	chunkInt, _ :=strconv.Atoi(chunk)
	chunkSizeInt, _ :=strconv.Atoi(chunkSize)
	if chunkInt>=chunkSizeInt{
		fmt.Println("上传完毕！");
		//
		filePath := uploadCreateDir(bucket, fileName)
		cachePath=Config.Config.StorePath +cachePath
		err := uploadChunkMergeTmp(filePath, cachePath,  chunkSize)
		_=os.Remove(cachePath)
		if err!=nil{
			output.Fail(context, err)
			return
		}

		output.Success(context, gin.H{
			"fileFull": Config.Config.Website + bucket + "/" + fileName,
			"file": bucket + "/" + fileName,
		})
		return
	}


	header, err := uploadBeforeHandle(context)
	if chunkInt==0{
		isAllow:=fileTypeFileHeaderCheck(header)
		if !isAllow{
			output.Fail(context, errors.New("非法文件类型"))
			return
		}
	}

	if fileNameExt==""{
		output.Fail(context, errors.New("文件后缀获取失败"))
		return
	}
	// 保存分片文件
	filePath := uploadCreateDir(cachePath, chunk)
	if err != nil {
		output.Fail(context, err)
		return
	}
	err = context.SaveUploadedFile(header, filePath)
	if err!=nil{
		output.Fail(context, err)
		return
	}
	output.Success(context,nil)
	return
}

func uploadChunkMergeTmp(newFilePath string ,cachePath string,chunkSize string)(err error)  {
	newFile, err := os.Create(newFilePath)
	if err != nil {
		return
	}

	size,_:=strconv.Atoi(chunkSize)
	var  (
		tmpFile *os.File
		tmpByte []byte
	)
	for  i:=0;i<size;i++{
		cacheFile:=cachePath+"/"+strconv.Itoa(i)
		tmpFile, err = os.Open(cacheFile)
		if err!=nil{
			break
		}
		tmpByte, err = ioutil.ReadAll(tmpFile)
		if err != nil {
			break
		}
		_, err = newFile.Write(tmpByte)
		if err != nil {
			break
		}
		err= tmpFile.Close()
		if err != nil {
			break
		}
		err = os.Remove(cacheFile)
		if err != nil {
			break
		}
	}
	err = newFile.Close()
	return
}